"""
@Author    : ghenyar
@Time      : 2025/9/3 16:19
@File      : admin_service
@Desc      : 管理员
"""
from typing import List, Any

from sqlalchemy import or_
from sqlalchemy.ext.asyncio import AsyncSession

from app.admin.schemas.admin import AdminSerialize, AdminSchema, AdminUserInfo
from app.admin.service.role_service import RoleService
from app.common.model_querier import ModelQuerier
from app.common.page_result import PageResult
from app.common.tools import get_password_hash
from app.models.admin_model import AdminModel, AdminRoleModel
from app.utils.log import LoggingUtil
from sqlalchemy.dialects.mysql import insert as mysql_insert


class AdminService:
    # 日志
    logger = LoggingUtil(f"{__name__}.AdminService")

    @classmethod
    async def admin_lists(cls, db: AsyncSession, page: int, pageSize: int, key: str = None,
                          status: int = None) -> PageResult | None:
        """
        管理员列表
        :param db:
        :param page:
        :param pageSize:
        :param key:
        :param status:
        :return:
        """
        conditions = []
        if key:
            conditions.append(or_(
                AdminModel.account.contains(key),
                AdminModel.nickname.contains(key),
                AdminModel.phone.contains(key),
            ))
        if status is not None:
            conditions.append(AdminModel.is_locked == bool(status))

        querier = ModelQuerier(db, AdminModel)
        if conditions:
            querier = querier.where(*conditions)

        lists = await querier.order_by(AdminModel.id.desc()).pagination(page, pageSize)

        # 处理数据
        async def format_admin(admin_item):
            admin_orm = await AdminSerialize.from_orm(admin_item)
            role_ids = await cls.get_admin_role(db, admin_item.id)
            admin_orm.role = role_ids[0] if role_ids else None
            if len(role_ids) != 0:
                roles = await RoleService.get_role_by_ids(db, role_ids)
                admin_orm.role_name = [role.name for role in roles]
            return admin_orm

        lists.items = [await format_admin(admin) for admin in lists.items]
        return lists

    @classmethod
    async def create_or_update(cls, db: AsyncSession, data: AdminSchema) -> bool | dict[str, Any]:
        """
        新增、编辑管理员
        :param db:
        :param data:
        :return:
        """
        try:
            save_data = data.model_dump(exclude_unset=True, exclude={"id", "role", "password"})
            if data.password:
                save_data["password"] = get_password_hash(data.password)

            if data.id is None or data.id == 0:
                admin = AdminModel(**save_data)
                db.add(admin)
                await db.commit()
                admin_id = admin.id
            else:
                await ModelQuerier(db, AdminModel).where(AdminModel.id == data.id).update(**save_data)
                admin_id = data.id

            await cls._update_or_create_admin_role(db, admin_id, data.role)

            return True
        except Exception as e:
            cls.logger.error(f"新增或编辑管理员失败！{str(e)}")
            return False

    @staticmethod
    async def _update_or_create_admin_role(db: AsyncSession, admin_id: int, role_id: int | List[int]):
        """
        幂等维护管理员-角色关联
        1. 先删旧数据
        2. 再批量 upsert 新数据
        """
        # 统一转 list
        roles: List[int] = [role_id] if isinstance(role_id, int) else role_id
        roles = [int(r) for r in roles]  # 再强转一次，防传字符串

        await ModelQuerier(db, AdminRoleModel).where(AdminRoleModel.id == admin_id).delete()

        # 2. 批量 upsert（MySQL 语法）
        insert_stmt = mysql_insert(AdminRoleModel).values([
            {"admin_id": admin_id, "role_id": rid} for rid in roles
        ])
        await db.execute(insert_stmt.on_duplicate_key_update(role_id=insert_stmt.inserted.role_id))
        await db.commit()

    @classmethod
    async def del_admin(cls, db: AsyncSession, admin_id) -> bool | dict[str, Any]:
        """
        删除管理员
        :param db:
        :param admin_id: 所需删除数据的id
        :return: True：成功
        """
        try:
            await ModelQuerier(db, AdminModel).where(AdminModel.id == admin_id).delete()
            return True
        except Exception as e:
            cls.logger.error(str(e))
            return {"message": str(e)}


    @staticmethod
    async def get_admin_by_account(db: AsyncSession, account: str) -> AdminModel | None:
        """
        根据账号获取管理员
        :param db: 数据库会话
        :param account: 管理员账号
        :return: 管理员数据
        """
        return await ModelQuerier(db, AdminModel).where(AdminModel.account == account.strip()).get_one()

    @staticmethod
    async def get_admin_role(db: AsyncSession, admin_id: int) -> List[int] | None:
        """
        根据管理员id获取所属角色id
        :param db: 数据库会话
        :param admin_id: 管理员id
        :return: 角色id列表  [role_id,role_id]
        """
        return await ModelQuerier(db, AdminRoleModel).where(AdminRoleModel.admin_id == admin_id).get_list(
            AdminRoleModel.role_id)

    @classmethod
    async def update_admin_dict(cls, db: AsyncSession, admin_id: int, data: dict) -> bool:
        """
        管理员根据管理员id更新数据
        :param db: 数据库会话
        :param admin_id: 管理员id
        :param data: 更新数据
        :return:
        """
        try:
            success = await ModelQuerier(db, AdminModel).where(AdminModel.id == admin_id).update_one(**data)
            return bool(success)
        except Exception as e:
            await db.rollback()
            cls.logger.error(str(e))
            return False

    @classmethod
    async def get_admin_by_id(cls, db: AsyncSession, admin_id: int) -> AdminModel | None:
        """
        根据id获取管理员数据
        :param db: 数据库会话
        :param admin_id: 管理员id
        :return: 管理员数据
        """
        return await ModelQuerier(db, AdminModel).get_by_id(admin_id)

    @classmethod
    async def get_login_admin_info(cls, db: AsyncSession,  admin_id: int) -> AdminSerialize | None:
        """
        根据管理员id获取管理详细数据
        :param db: 数据库会话
        :param admin_id: 管理员id
        :return: 管理员数据
        """
        admin = await cls.get_admin_by_id(db,admin_id)
        if not admin:
            return None
        admin_data = await AdminUserInfo.from_orm(admin)
        if admin.is_super:
            admin_data.role_name = "超级管理员"
        else:
            role_ids = await cls.get_admin_role(db,admin.id)
            if role_ids:
                roles = await RoleService.get_role_by_ids(db,role_ids)
                admin_data.role_name = [role.name for role in roles]
        return admin_data
